package unit

import (
	"os"

	"gddgame.cc/galaxy"
	"gddgame.cc/galaxy/common/feature/dwarf"
	"gddgame.cc/galaxy/common/feature/phantom"
	"gddgame.cc/galaxy/project/neutron/neutron/controller"
	"gddgame.cc/galaxy/project/neutron/neutron/logic"
	"gddgame.cc/galaxy/server/composer"
	"gddgame.cc/galaxy/utils"
	"gddgame.cc/galaxy/utils/def"
	"gddgame.cc/galaxy/utils/request"
	"github.com/olekukonko/tablewriter"
	"github.com/spf13/cobra"
)

var (
	config *logic.Config
)

type I struct {
	composer.Composer `inject:""`
}

type Response struct {
	Status  int         `json:"status"`
	Result  interface{} `json:"result"`
	Message interface{} `json:"message"`
}

var Command = &cobra.Command{
	Use:   "unit",
	Short: "计算单元管理",
	Long:  `通过命令行启动计算单元，并且可以查看运行状态`,
}
var startCommand = &cobra.Command{
	Use:   "start [name] [target]",
	Short: "start and daemonize an unit",
	Args:  cobra.ExactArgs(2),
	Run: func(cmd *cobra.Command, args []string) {
		if err := InitEnv(); err != nil {
			dwarf.Context.Error(err)
			return
		}
		force, _ := cmd.PersistentFlags().GetBool("force")
		if err := controller.ValidUnit(dwarf.Context, args[0], args[1], force); err != nil {
			dwarf.Context.Error(err)
			return
		}
		var result Response
		agent := request.New()
		agent.SetLogger(dwarf.Context)
		agent.Post("http://" + config.Address + "/unit/start").Type("json").Send(map[string]interface{}{
			"name":   args[0],
			"target": args[1],
			"force":  force,
		})
		agent.EndStruct(&result)
		dwarf.Context.Println(result)
		ShowUnits(dwarf.Context)
	},
}
var restartCommand = &cobra.Command{
	Use:   "restart [name]",
	Short: "restart an unit",

	Args: cobra.ExactArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		if err := InitEnv(); err != nil {
			dwarf.Context.Error(err)
			return
		}
		force, _ := cmd.PersistentFlags().GetBool("force")
		var result Response
		agent := request.New()
		agent.SetLogger(dwarf.Context)
		agent.Put("http://" + config.Address + "/unit/restart").Type("json").Send(map[string]interface{}{
			"name":  args[0],
			"force": force,
		})
		agent.EndStruct(&result)
		dwarf.Context.Println(result)
		ShowUnits(dwarf.Context)
	},
}
var stopCommand = &cobra.Command{
	Use:   "stop",
	Short: "stop an unit",
	Args:  cobra.ExactArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		if err := InitEnv(); err != nil {
			dwarf.Context.Error(err)
			return
		}
		var result Response
		agent := request.New()
		agent.SetLogger(dwarf.Context)
		agent.Put("http://" + config.Address + "/unit/stop").Type("json").Send(map[string]interface{}{
			"name": args[0],
		})
		agent.EndStruct(&result)
		dwarf.Context.Println(result)

		ShowUnits(dwarf.Context)
	},
}
var psCommand = &cobra.Command{
	Use:   "ps",
	Short: "list all processes",
	Args:  cobra.ExactArgs(0),
	Run: func(cmd *cobra.Command, args []string) {
		if err := InitEnv(); err != nil {
			dwarf.Context.Error(err)
			return
		}
		ShowUnits(dwarf.Context)
	},
}

func init() {
	startCommand.PersistentFlags().Bool("force", false, "force update same name")
	Command.AddCommand(startCommand)
	restartCommand.PersistentFlags().Bool("force", false, "force update if running")
	Command.AddCommand(restartCommand)
	Command.AddCommand(stopCommand)
	Command.AddCommand(psCommand)
}

func InitEnv() error {
	config = &logic.Config{}
	if err := galaxy.RegisterConfig("neutron", config, true); err != nil {
		return err
	}
	cloudConfig := &phantom.Config{}
	if err := galaxy.RegisterConfig("cloud", cloudConfig, true); err != nil {
		return err
	}
	platform, err := phantom.PlatformWithConfig(cloudConfig)
	if err != nil {
		return err
	}
	if err := logic.Init(config, platform, false); err != nil {
		return err
	}
	return nil
}

func ShowUnits(ctx def.Context) {
	units, err := controller.ShowAllUnit(ctx)
	if err != nil {
		ctx.Error(err)
		return
	}
	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"Name", "Type", "Pid", "Cpu", "Mem", "Restart", "Status", "WorkDir"})
	for _, unit := range units {
		// show table
		if unit == nil {
			continue
		}

		t := utils.ToInt(unit["type"])
		status := utils.ToInt(unit["status"])

		row := make([]string, 8)
		row[0] = utils.ToString(unit["name"])
		switch logic.UnitType(t) {
		case logic.ProcessType:
			row[1] = "Process"
		case logic.DockerType:
			row[1] = "Docker"
		}
		row[2] = utils.ToString(unit["pid"])
		row[3] = utils.ToString(unit["cpu"])
		mem := utils.ToInt(unit["mem"])
		memUnit := "KB"
		if mem > 1024 {
			mem = mem / 1024
			memUnit = "MB"
			if mem > 1024 {
				mem = mem / 1024
				memUnit = "GB"
			}
		}
		row[4] = utils.ToString(mem) + memUnit
		row[5] = utils.ToString(unit["restart"])
		switch logic.UnitStatus(status) {
		case logic.RunningStatus:
			row[6] = "Running"
		case logic.RollbackStatus:
			row[6] = "Rollback"
		case logic.ErrorStatus:
			row[6] = "Error"
			// 错误状态，已经停止运行
			row[3] = "-"
			row[4] = "-"
		}
		row[7] = utils.ToString(unit["workDir"])

		table.Append(row)
	}
	table.Render()
}
